import tkinter as tk
from tkinter import font as tkfont
import re


# 辅助函数，用于显示详细的错误提示信息
def show_detailed_error_message(message):
    error_window = tk.Toplevel()
    error_window.title("错误提示")

    error_font = tkfont.Font(family="阿里巴巴普惠体 2 65 Medium", size=12)
    error_label = tk.Label(error_window, text=message, font=error_font)
    error_label.pack(pady=10)

    ok_button = tk.Button(error_window, text="确定", command=error_window.destroy)
    ok_button.pack(pady=5)


# 计算两个角度所确定圆弧的中点角度
def get_arc_midpoint(angle1, angle2):
    angle1_degrees = float(angle1)
    angle2_degrees = float(angle2)

    # 考虑两种情况，angle1到angle2的顺时针和逆时针方向
    mid_angle1 = (angle1_degrees + angle2_degrees) / 2
    mid_angle2 = (angle1_degrees + angle2_degrees + 360) / 2 if angle1_degrees > angle2_degrees else (angle1_degrees + angle2_degrees - 360) / 2

    return mid_angle1, mid_angle2


# 星座列表和星座对应的角度范围（可考虑将这些定义为配置文件中的条目）
SIGNS = ["白羊", "金牛", "双子", "巨蟹", "狮子", "处女", "天秤", "天蝎", "射手", "摩羯", "水瓶", "双鱼"]
ANGLE_RANGES = [(0.0, 30.0), (30.0, 60.0), (60.0, 90.0), (90.0, 120.0), (120.0, 150.0), (150.0, 180.0),
                (180.0, 210.0), (210.0, 240.0), (240.0, 270.0), (270.0, 300.0), (300.0, 330.0), (330.0, 360.0)]


def get_sign_angle(sign):
    for i, s in enumerate(SIGNS):
        if s == sign:
            return ANGLE_RANGES[i]
    raise ValueError(f"未知的星座名称 '{sign}'")


# 验证输入的星座名称是否有效，并提供详细错误信息
def validate_sign(sign):
    if sign not in SIGNS:
        raise ValueError(f"输入的星座名称 '{sign}' 无效，请重新输入。")
    return True


# 验证输入的星座度数是否在有效范围内，并提供详细错误信息
def validate_degree(angle_str, sign):
    # 使用正则表达式验证度数字符串的格式
    match = re.match(r'^(\d+)\.(\d{1,2})$', angle_str)
    if not match:
        raise ValueError(f"输入的星座 '{sign}' 的度数 '{angle_str}' 格式错误，应为度.分形式（分可以是1位或2位小数，仅1位小数时前面补0）。")

    degree = int(match.group(1))
    fraction = int(match.group(2))

    # 检查分是否超过60，如果超过则进位到度
    if fraction >= 60:
        degree += 1
        fraction -= 60

    if not (0 <= degree < 30):
        raise ValueError(f"输入的星座 '{sign}' 的度数 '{angle_str}' 中的度应在0到29之间，请重新输入。")
    if not (0 <= fraction <= 59):
        raise ValueError(f"输入的星座 '{sign}' 的度数 '{angle_str}' 中的分应在0到59之间，请重新输入。")

    # 返回度数（包含分的小数部分），这里要重新计算正确的小数形式
    return degree + fraction / 60


# 清空所有输入框的内容
def clear_entries():
    sign1_entry.delete(0, tk.END)
    angle1_entry.delete(0, tk.END)
    sign2_entry.delete(0, tk.END)
    angle2_entry.delete(0, tk.END)


# 根据用户输入的两个星座及度数，计算它们之间圆弧的两个中点度数并输出结果
def calculate_midpoint_between_signs():
    try:
        sign1 = sign1_entry.get()
        validate_sign(sign1)

        angle1_str = angle1_entry.get()
        angle1 = validate_degree(angle1_str, sign1)

        sign2 = sign2_entry.get()
        validate_sign(sign2)

        angle2_str = angle2_entry.get()
        angle2 = validate_degree(angle2_str, sign2)

        start_angle_sign1, end_angle_sign1 = get_sign_angle(sign1)
        start_angle_sign2, end_angle_sign2 = get_sign_angle(sign2)

        full_angle1 = start_angle_sign1 + angle1
        full_angle2 = start_angle_sign2 + angle2

        # 确保full_angle1小于full_angle2，如果不是，则交换它们（以便后续计算更简洁）
        if full_angle1 > full_angle2:
            full_angle1, full_angle2 = full_angle2, full_angle1

        # 计算两个中点角度（考虑角度的周期性）
        mid_angle1 = (full_angle1 + full_angle2) / 2
        mid_angle2 = (full_angle1 + full_angle2 + 360) / 2 - 360  # 顺时针方向的中点

        # 如果mid_angle1或mid_angle2小于0（由于浮点数精度问题可能会出现这种情况），则将其调整为大于0的角度
        if mid_angle1 < 0:
            mid_angle1 += 360
        if mid_angle2 < 0:
            mid_angle2 += 360

        # 计算中点星座及度数（路径一和路径二），并转换回度数和分钟的格式
        result_sign1, result_angle1_deg = get_midpoint_sign_and_angle(mid_angle1)
        result_angle1_min = int((result_angle1_deg - int(result_angle1_deg)) * 60)
        result_angle1 = f"{int(result_angle1_deg)}度{result_angle1_min:02d}分"

        result_sign2, result_angle2_deg = get_midpoint_sign_and_angle(mid_angle2)
        result_angle2_min = int((result_angle2_deg - int(result_angle2_deg)) * 60)
        result_angle2 = f"{int(result_angle2_deg)}度{result_angle2_min:02d}分"

        # 输出结果
        result_text = f"中点星座及度数（路径一）: {result_sign1} {result_angle1}\n"
        result_text += f"中点星座及度数（路径二）: {result_sign2} {result_angle2}\n"
        result_label.config(text=result_text)
    except ValueError as e:
        show_detailed_error_message(f"{e}")

# 辅助函数：根据中点角度获取中点星座及度数（返回度数的小数形式）
def get_midpoint_sign_and_angle(mid_angle):
    for i, (start_angle, end_angle) in enumerate(zip([0.0] + [30.0 * i for i in range(0, 12)], [30.0 * i for i in range(1, 13)])):
        if start_angle <= mid_angle < end_angle:
            result_sign = SIGNS[i]
            result_angle = mid_angle % 30  # 返回0-29.999...范围内的度数小数形式
            return result_sign, result_angle
    raise ValueError("无法确定星座中点及度数，请检查输入的角度值是否有效。")


# 辅助函数，用于显示关于信息的窗口
def show_about_info():
    about_window = tk.Toplevel()
    about_window.title("关于")

    about_font = tkfont.Font(family="阿里巴巴普惠体 2 65 Medium", size=12)
    about_text = ("占星学中点星座计算器v1.2\n\nv1.2解决中点星座超过 60 分未进位的问题。\nv1.1解决中点星座路径二计算错误的问题。\nv1.0有了GUI界面，更友善的提示功能。\n\n此程序由"
                  "PRSPairsMask开发，\n用于辅助占星学中点星座计算。\n2024年11月30日")

    about_label = tk.Label(about_window, text=about_text, font=about_font)
    about_label.pack(pady=10)

    ok_button = tk.Button(about_window, text="确定", command=about_window.destroy)
    ok_button.pack(pady=5)


root = tk.Tk()
root.title("占星学中点星座计算器v1.2")

# 设置窗口大小
root.geometry("350x480")

# 设置通用间距常量
PADDING = 5

# 设置字体样式为阿里巴巴普惠体 2 65 Medium， size=12
custom_font = tkfont.Font(family="阿里巴巴普惠体 2 65 Medium", size=12)
root.option_add("*Font", custom_font)

# 第一个星座相关输入
sign1_frame = tk.Frame(root)
sign1_frame.pack(pady=PADDING)

sign1_label = tk.Label(sign1_frame, text="第一个星座:")
sign1_label.pack()

sign1_entry = tk.Entry(sign1_frame)
sign1_entry.pack(pady=PADDING)

angle1_frame = tk.Frame(root)
angle1_frame.pack(pady=PADDING)

angle1_label = tk.Label(angle1_frame, text="度数（度.分）:")
angle1_label.pack()

angle1_entry = tk.Entry(angle1_frame)
angle1_entry.pack(pady=PADDING)

# 第二个星座相关输入
sign2_frame = tk.Frame(root)
sign2_frame.pack(pady=PADDING)

sign2_label = tk.Label(sign2_frame, text="第二个星座:")
sign2_label.pack()

sign2_entry = tk.Entry(sign2_frame)
sign2_entry.pack(pady=PADDING)

angle2_frame = tk.Frame(root)
angle2_frame.pack(pady=PADDING)

angle2_label = tk.Label(angle2_frame, text="度数（度.分）:")
angle2_label.pack()

angle2_entry = tk.Entry(angle2_frame)
angle2_entry.pack(pady=PADDING)

# 创建一个框架来包含计算和清空按钮
button_frame = tk.Frame(root)
button_frame.pack(pady=PADDING)

calculate_button = tk.Button(button_frame, text="计算", command=calculate_midpoint_between_signs)
calculate_button.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")  # 使用grid布局，并设置sticky来使按钮填充单元格

clear_button = tk.Button(button_frame, text="清空", command=clear_entries)
clear_button.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")  # 使用grid布局，并设置sticky来使按钮填充单元格

# 创建并添加关于按钮
about_button = tk.Button(root, text="关于", command=show_about_info)
about_button.pack(pady=PADDING)

# 结果标签也使用grid布局，以便更好地控制其在窗口中的位置
result_label_frame = tk.Frame(root)
result_label_frame.pack(pady=PADDING)
result_label = tk.Label(result_label_frame, text="")
result_label.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")

root.mainloop()